const compileUtil={
    getVal(expr,vm){
        const arr = expr.split('.')
        //reduce() 方法接收一个函数作为累加器，数组中的每个值（从左到右）开始缩减，最终计算为一个值
        return arr.reduce((data,currentValue)=>{
            return data[currentValue]
        },vm.$data)
    },
    setVal(expr,vm,inputVal){
        return expr.split('.').reduce((data,currentValue)=>{
             data[currentValue] = inputVal
        },vm.$data)
    },
    getContentVal(expr,vm){
        return expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
            return this.getVal(args[1],vm)
        })
    },
    text(node,expr,vm){
        let value
        if(expr.indexOf('{{') !== -1){
                value = expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
                    new Watcher(vm,args[1],()=>{
                        this.updater.textUpdater(node,this.getContentVal(expr,vm))
                    })
                    return this.getVal(args[1],vm)
            })
        }else{
           value = this.getVal(expr,vm)
        }
        this.updater.textUpdater(node,value)
    },
    html(node,expr,vm){
        let value = this.getVal(expr,vm)
        new Watcher(vm,expr,(newVal)=>{
            this.updater.htmlUpdater(node,newVal)
        })
        this.updater.htmlUpdater(node,value)
    },
    model(node,expr,vm){
        const value = this.getVal(expr,vm)
        //绑定更新函数 数据=>视图
        new Watcher(vm,expr,(newVal)=>{
            this.updater.modelUpdater(node,newVal)
        })
        // 视图=>数据=>视图
        node.addEventListener('input',(e)=>{
            //设置值
            this.setVal(expr,vm,e.target.value)
        })
        this.updater.modelUpdater(node,value)
    },
    on(node,expr,vm,eventName){
        let fn = vm.$options.methods && vm.$options.methods[expr]
        node.addEventListener(eventName,fn.bind(vm),false)
    },
    bind(node,expr,vm,attrName){

    },
    updater:{
        textUpdater(node,value){
            node.textContent = value
        },
        htmlUpdater(node,value){
            node.innerHTML = value
        },
        modelUpdater(node,value){
            node.value = value
        }
    }
}
class Compile{
    constructor(el,vm){
        this.el = this.isElementNode(el) ? el : document.querySelector(el)
        this.vm = vm
        //获取文档碎片对象，放入内存会减少页面的回流重绘
        const fragment = this.nodeFragment(this.el)
        //编译模板
        this.compile(fragment)
        //追加子元素到根元素
        this.el.appendChild(fragment)
    }
    isDirective(attrName){
        return attrName.startsWith('v-')
    }
    isEventName(attrName){
        return attrName.startsWith('@')
    }
    isElementNode(node){
        return node.nodeType === 1
    }
    nodeFragment(el){
        //创建一个虚拟的节点对象
        const fragment = document.createDocumentFragment()
        let fistChild
        // el.firstChild返回首个子节点后，父节点会改变
        while(fistChild = el.firstChild){
            fragment.appendChild(fistChild)
        }
        return fragment
    }
    compile(fragment){
        //获取子节点
        const [...childNodes] = fragment.childNodes
        childNodes.forEach(child=>{
            if(this.isElementNode(child)){
                //取元素节点,编译元素节点
               this.compileElement(child)
            }else{
                //取文本节点，编译文本节点
                this.compileText(child)
            }
            //递归遍历嵌套的子节点
            if(child.childNodes && child.childNodes.length){
                this.compile(child)
            }
        })
    }
    //编译元素节点
    compileElement(node){
        const [...attributes] = node.attributes;
        attributes.forEach(attr=>{
            const {name,value} = attr
            if(this.isDirective(name)){
                //是一个指令 v-text v-html v-model v-on:click等等
                const [,directive] = name.split('-') // text html model on:click等放在arr[1]
                const [dirName,eventName] = directive.split(':')
                // 更新数据 数据驱动视图
                compileUtil[dirName](node,value,this.vm,eventName)
                //删除有指令的标签上的属性
                node.removeAttribute('v-'+directive)
            }else if(this.isEventName(name)){
                let [,eventName] = name.split('@')
                compileUtil['on'](node,value,this.vm,eventName)
            }
        })
    }
    //编译文本节点
    compileText(node){
        // {{}} v-text
        const content = node.textContent
        if(/\{\{(.+?)\}\}/.test(content)){
          compileUtil['text'](node,content,this.vm)
        }
    }
}
class MVue{
    constructor(options){
        this.$options = options
        this.$el = options.el
        this.$data = options.data
        if(this.$el){
            //1、实现一个数据的观察者
            new Observer(this.$data)
            //2、实现一个指令解析器
            new Compile(this.$el,this)
            //代理this.$data
            this.proxyData(this.$data)
        }
    }
    proxyData(data){
        for(const key in data){
            Object.defineProperty(this,key,{
                get(){
                    return data[key]
                },
                set(newVal){
                    data[key] = newVal
                }
            })
        }
    }


}